<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>拖拽交换动画示例</title>
  <style>
      body {
          font-family: Arial, sans-serif;
          margin: 20px;
          padding: 0;
      }
      ul {
          list-style-type: none;
          padding: 0;
      }
      li {
          padding: 10px;
          margin: 5px 0;
          background-color: #f0f0f0;
          border: 1px solid #ccc;
          cursor: grab;
          transition: transform 0.3s ease, opacity 0.3s ease;
      }
      li.dragging {
          opacity: 0.5;
          transform: scale(1.05);
      }
      li.over {
          border: 2px solid #007BFF;
      }
  </style>
</head>
<body>

<ul id="itemList"></ul>

<script>
  let items = ['Item 1', 'Item 2', 'Item 3', 'Item 4', 'Item 5'];
  const itemList = document.getElementById('itemList');

  function renderList() {
    itemList.innerHTML = '';
    items.forEach((item, index) => {
      const li = document.createElement('li');
      li.textContent = item;
      li.draggable = true;
      li.dataset.index = index;

      // 绑定拖拽事件
      li.addEventListener('dragstart', dragStart);
      li.addEventListener('dragover', dragOver);
      li.addEventListener('drop', drop);
      li.addEventListener('dragleave', dragLeave);

      itemList.appendChild(li);
    });
  }

  function dragStart(e) {
    e.dataTransfer.effectAllowed = 'move';
    e.dataTransfer.setData('text/plain', e.target.dataset.index);
    e.target.classList.add('dragging');
  }

  function dragOver(e) {
    e.preventDefault(); // 必须调用以允许放下
    const target = e.target;
    if (target && target.nodeName === 'LI') {
      target.classList.add('over');
    }
    // 恢复过渡
    requestAnimationFrame(() => {
      draggedElement.style.transition = 'transform 0.3s ease, opacity 0.3s ease';
      targetElement.style.transition = 'transform 0.3s ease, opacity 0.3s ease';

      // 应用动画
      const targetRect = targetElement.getBoundingClientRect();
      const draggedRect = draggedElement.getBoundingClientRect();

      // 使用 transform 进行动画
      draggedElement.style.transform = `translate(${targetRect.left - draggedRect.left}px, ${targetRect.top - draggedRect.top}px)`;
      targetElement.style.transform = `translate(${draggedRect.left - targetRect.left}px, ${draggedRect.top - targetRect.top}px)`;

      // 动画结束后清除样式
      setTimeout(() => {
        draggedElement.style.transition = '';
        targetElement.style.transition = '';
        draggedElement.style.transform = '';
        targetElement.style.transform = '';
        renderList(); // 重新渲染列表
      }, 300); // 动画持续时间
    });
  }

  function drop(e) {
    e.preventDefault();
    const draggedIndex = e.dataTransfer.getData('text/plain');
    const targetIndex = e.target.dataset.index;

    // 交换位置并平滑过渡
    if (draggedIndex !== targetIndex) {
      const draggedItem = items[draggedIndex];
      items.splice(draggedIndex, 1);
      items.splice(targetIndex, 0, draggedItem);

      // 动画效果
      const draggedElement = itemList.children[draggedIndex];
      const targetElement = itemList.children[targetIndex];

      // 动画交换
      draggedElement.style.transition = 'none'; // 取消过渡
      targetElement.style.transition = 'none'; // 取消过渡

      // 重新渲染列表
      renderList();


    }
  }

  function dragLeave(e) {
    e.target.classList.remove('over');
  }

  renderList();
</script>

</body>
</html>